#include "../utils.h"
#include "../system.h"


#ifdef XG_LINUX

#include <termios.h>
#include <sys/stat.h>
#include <sys/time.h>

int getch()
{
	struct termios tm;
	struct termios old;

	int ch;
	int fd = STDIN_FILENO;

	if (tcgetattr(fd, &tm) < 0) return XG_ERROR;

	old = tm;
	cfmakeraw(&tm);

	if (tcsetattr(fd, TCSANOW, &tm) < 0) return XG_ERROR;

	ch = fgetc(stdin);

	if (tcsetattr(fd, TCSANOW, &old) < 0) return XG_ERROR;

	return ch;
}

#else

void usleep(unsigned long usec)
{
	unsigned long ms = usec / 1000;

	if (ms > 0)
	{
		Sleep(ms);

		usec -= ms * 1000;
	}

	if (usec > 0)
	{
		LARGE_INTEGER litmp;

		QueryPerformanceFrequency(&litmp);

		double end = usec * litmp.QuadPart * 0.000001;

		QueryPerformanceCounter(&litmp);

		end += litmp.QuadPart;

		do
		{
			QueryPerformanceCounter(&litmp);
		}
		while(litmp.QuadPart < end);
	}
}

#endif

BOOL DaemonInit()
{
	fflush(stdout);
	
#ifdef XG_LINUX
	pid_t pid = fork();
	
	if (pid < 0) return FALSE;
	if (pid > 0) exit(0);

	setsid(); umask(0);
#endif

	return TRUE;
}

BOOL ClearConsole()
{
#ifdef XG_LINUX
	return system("clear") >= 0;
#else
	return system("cls") >= 0;
#endif
}

void SystemExit(int code)
{
#ifdef XG_LINUX
	kill(getpid(), SIGINT);
	sync();
	sleep(1);
	_exit(code);
#else
	fflush(stdout);
	TerminateProcess(GetCurrentProcess(), code);
#endif
}

unsigned long long GetTime()  
{
#ifdef XG_LINUX
	struct timeval tv;
	struct timezone tz;

	gettimeofday(&tv, &tz);

	return tv.tv_sec * 1000000 + tv.tv_usec;
#else
	FILETIME ft;

	GetSystemTimeAsFileTime(&ft);  

	return ((((unsigned long long)(ft.dwHighDateTime) << 32) | ft.dwLowDateTime) - 116444736000000000L) / 10;
#endif
}

const char* GetLocaleCharset()
{
#ifdef _MSC_VER
	static char charset[] = "gbk";
#else
	static char charset[32] = {0};
#endif

	if (*charset) return charset;

	int idx = 0;
	char lang[64] = {0};
	const char* str = getenv("LANG");

	if (str == NULL || *str == 0) return "utf-8";

	while (*str && idx < ARR_LEN(lang) - 1)
	{
		lang[idx++] = tolower(*str++);
	}

	if (strstr(lang, "gbk"))
	{
		strcpy(charset, "gbk");
	}
	else if (strstr(lang, "utf-8"))
	{
		strcpy(charset, "utf-8");
	}
	else if (strstr(lang, "gb2312"))
	{
		strcpy(charset, "gb2312");
	}
	else
	{
		const char* tmp = strrchr(lang, '.');

		strncpy(charset, (tmp ? tmp + 1 : lang), sizeof(charset) - 1);
	}

	return charset;
}

void SystemPause(const char* msg)
{
	if (msg == NULL) msg = "\npress any key to continue\n";

	if (*msg) puts(msg);

	fflush(stdout);
	getch();
}

BOOL GetDateTime(stDateTime* dt, const time_t* tm)
{
	time_t now;
	struct tm tmp;

	if (tm == NULL)
	{
		time(&now);
		tm = &now;
	}

	localtime_r(tm, &tmp);

	dt->year = tmp.tm_year + 1900;
	dt->month = tmp.tm_mon + 1;
	dt->yday = tmp.tm_yday + 1;
	dt->wday = tmp.tm_wday;
	dt->mday = tmp.tm_mday;

	if (dt->wday == 0) dt->wday = 7;

	dt->hour = tmp.tm_hour;
	dt->min = tmp.tm_min;
	dt->sec = tmp.tm_sec;

	return TRUE;
}

int GetHostInteger(const char* host)
{
	u_char arr[4] = {0};
	const char* str = host;

	arr[0] = atoi(str++);
	str = strchr(str, '.');

	if (str == NULL) return 0;

	arr[1] = atoi(++str);
	str = strchr(str, '.');
	
	if (str == NULL) return 0;

	arr[2] = atoi(++str);
	str = strchr(str, '.');

	if (str == NULL) return 0;

	arr[3] = atoi(++str);
	
	return (arr[0] << 24) + (arr[1] << 16) + (arr[2] << 8) + arr[3];
}

char* TrimString(char* str, const char* space)
{
	char* ptr = NULL;

	ptr = (char*)SkipStartString(str, space);

	if (*ptr == 0)
	{
		*str = 0;

		return str;
	}

	str = ptr + strlen(ptr) - 1;

	while (str > ptr && strchr(space, *str)) *str-- = 0;

	return ptr;
}

int GetStringCount(const char* str, const char* src)
{
	int count = 0;

	if (*str == 0) return 0;

	if (src[1] == 0)
	{
		char ch = *src;

		while (*str)
		{
			if (*str++ == ch) ++count;
		}
	}
	else
	{
		const char* end = NULL;
		const char* start = NULL;
		const int LEN = (int)(strlen(src));

		start = str;

		while (TRUE)
		{
			end = strstr(start, src);

			if (end == NULL)
			{
				size_t len = strlen(start);

				if (len > 0 && '\r' == start[len - 1]) --len;

				break;
			}
			else
			{
				start = end + LEN;
				++count;
			}
		}
	}

	return count;
}

stCharBuffer GetTrimString(const char* str, const char* space)
{
	size_t len = 0;
	stCharBuffer buffer;
	const char* ptr = NULL;

	buffer.val[0] = 0;

	ptr = SkipStartString(str, space);

	if (*ptr == 0) return buffer;

	len = strlen(ptr) - 1;

	while (len > 0 && strchr(space, ptr[len])) --len;

	if (len < 0) return buffer;

	memcpy(buffer.val, ptr, len + 1);
	buffer.val[len + 1] = 0;

	return buffer;
}

const char* SkipStartString(const char* str, const char* space)
{
	if (str == NULL || *str == 0) return str;

	while (*str && strchr(space, *str)) str++;

	return str;
}

char* GetLineValue(char* line, const char* tag, const char* spliter)
{
	char* ptr = NULL;
	size_t len = strlen(tag);

	line = (char*)SkipStartString(line, " \r\t");

	if (*line == 0 || strlen(line) <= len) return NULL;

	if (spliter == NULL) spliter = "=";

	if (memcmp(line, tag, len)) return NULL;

	line += len;
	len = strlen(spliter);

	line = (char*)SkipStartString(line, " \r\t");

	if (*line == 0 || strlen(line) <= len) return NULL;

	if (memcmp(line, spliter, len)) return NULL;

	ptr = line = (char*)SkipStartString(line + len, " \r\t");

	while (*ptr)
	{
		if (*ptr == ' ' || *ptr == '\r' || *ptr == '\t' || *ptr == '\n')
		{
			*ptr = 0;

			break;
		}

		++ptr;
	}

	return line;
}

stCharBuffer GetTruncatedString(const char* str, int len, const char* space)
{
	stCharBuffer dest;

	memcpy(dest.val, str, len);
	dest.val[len] = 0;
	
	return space ? GetTrimString(dest.val, space) : dest;
}

BOOL IsSmallEndianSystem()
{
	static u_int32 flag = 0;

	if (flag) return flag ? TRUE : FALSE;

	char data[] = {1, 0, 0, 0};
	u_int32* ptr = (u_int32*)(data);

	return (flag = *ptr) ? TRUE : FALSE;
}

BOOL IsAlphaString(const char* str)
{
	CHECK_FALSE_RETURN(isalpha(*str));

	++str;

	while (*str)
	{
		CHECK_FALSE_RETURN(isalpha(*str));

		++str;
	}

	return *str == 0;
}

BOOL IsAlnumString(const char* str)
{
	CHECK_FALSE_RETURN(isalnum(*str));

	++str;

	while (*str)
	{
		CHECK_FALSE_RETURN(isalnum(*str));

		++str;
	}

	return *str == 0;
}

BOOL IsNumberString(const char* str)
{
	const char* end = str + 16;

	CHECK_FALSE_RETURN((*str >= '0' && *str <= '9') || *str == '+' || *str == '-');

	if ((*str == '+' || *str == '-') && str[1] == 0) return FALSE;

	++str;

	while (*str && str < end)
	{
		CHECK_FALSE_RETURN(*str >= '0' && *str <= '9');

		++str;
	}

	return *str == 0;
}

BOOL IsAmountString(const char* str)
{
	const char* end = str + 16;

	CHECK_FALSE_RETURN((*str >= '0' && *str <= '9') || *str == '.' || *str == '+' || *str == '-');
	CHECK_FALSE_RETURN(GetStringCount(str, ".") < 2);

	++str;

	while (*str && str < end)
	{
		CHECK_FALSE_RETURN((*str >= '0' && *str <= '9') || *str == '.');

		++str;
	}

	return *str == 0;
}

void ReadPassword(char* str, int len, char echo, CHECK_PASSWORD_FUNC func)
{
	int i = 0;
	int ch = 0;
	BOOL flag = FALSE;
	
	if (isprint(echo)) flag = TRUE;

	while (i < len)
	{
		if ((ch = getch()) == '\b')
		{
			if (i == 0) continue;

			--i;

			if (flag) printf("\b \b");
		}
		else if (ch == 0 || ch == '\n' || ch == '\r')
		{
			break;
		}

		if (func == NULL)
		{
			if (isprint(ch))
			{
				if (flag) printf("%c", echo);

				str[i++] = (char)(ch);
			}
		}
		else if (func(ch))
		{
			if (flag) printf("%c", echo);

			str[i++] = (char)(ch);
		}
	}

	str[i] = 0;
}

BOOL SetConsoleTextColor(E_CONSOLE_COLOR color)
{
#ifdef XG_LINUX
	printf("\e[%dm", (int)(color));
#else
	static HANDLE console = NULL;

	if (console == NULL) console = GetStdHandle(STD_OUTPUT_HANDLE);

	CHECK_FALSE_RETURN(SetConsoleTextAttribute(console, color));
#endif
	return TRUE;
}